﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bluyel.Core
{
    /// <summary>
    /// Type builder manager.
    /// Manage creation of all types.
    /// </summary>
    public class TypeBuilderBase
    {
        FactoryMgrBase _factoryMgr;

        TypeMgrBase _typeMgr;

        //TypePhyMgr _typePhysQtyMgr;

        TypeFinderBase _typeFinder;

        //=====================================================================
        #region Constructor.

        //---------------------------------------------------------------------
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="factory"></param>
        public TypeBuilderBase(FactoryMgrBase factoryMgr, TypeMgrBase typeMgr, TypeFinderBase typeFinder)
        {
            _factoryMgr = factoryMgr;
            _typeMgr = typeMgr;
            //_typePhysQtyMgr = typePhysQtyMgr;
            _typeFinder = typeFinder;
        }
        #endregion

        //=====================================================================
        #region Public Create type methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create many types definitions with this single method.
        /// Return the count of types created.
        /// 
        /// Create only standard types: int, bool, string, double, struct,...
        /// </summary>
        /// <returns></returns>
        public void DefineAllTypes()
        {
            DefineAllTypeBasic();

            DefineTypeStruct();

            DefineTypeVoid();

            DefineTypePhyLength();
        }

        //---------------------------------------------------------------------
        public bool DefineAllTypeBasic()
        {
            DefineTypeInt();
            DefineTypeLong();
            DefineTypeString();
            DefineTypeBool();
            DefineTypeDouble();

            return true;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type int, can be defined/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeInt(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // already exists?
            if (_typeMgr.TypeInt != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeBasic typeInt = _factoryMgr.FactoryType.CreateTypeInt(name);
            if (!_typeMgr.AddTypeInt(typeInt))
                return null;
            
            return typeInt;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type int, can be defined/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeInt()
        {
            return DefineTypeInt(TypeDef.TypeIntName);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type long, can be defined/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeLong(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // already exists?
            if (_typeMgr.TypeLong != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeBasic typeLong = _factoryMgr.FactoryType.CreateTypeLong(name);
            if (!_typeMgr.AddTypeLong(typeLong))
                return null;

            return typeLong;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type long, can be defined/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeLong()
        {
            return DefineTypeLong(TypeDef.TypeLongName);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type double, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeDouble(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // already exists?
            if (_typeMgr.TypeDouble != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeBasic typeDouble = _factoryMgr.FactoryType.CreateTypeDouble(name);
            if (!_typeMgr.AddTypeDouble(typeDouble))
                return null;

            return typeDouble;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type double, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeDouble()
        {
            return DefineTypeDouble(TypeDef.TypeDoubleName);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type string, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeString(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // already exists?
            if (_typeMgr.TypeString != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeBasic typeString = _factoryMgr.FactoryType.CreateTypeString(name);
            if (!_typeMgr.AddTypeString(typeString))
                return null;

            return typeString;
        }
        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type string, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeString()
        {
            return DefineTypeString(TypeDef.TypeStringName);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type bool, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeBool(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // already exists?
            if (_typeMgr.TypeBool != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeBasic typeBool = _factoryMgr.FactoryType.CreateTypeBool(name);
            if (!_typeMgr.AddTypeBool(typeBool))
                return null;

            return typeBool;
        }
        //---------------------------------------------------------------------
        /// <summary>
        /// Define the basic type bool, can be define/created only one time.
        /// </summary>
        /// <returns></returns>
        public ITypeBasic DefineTypeBool()
        {
            return DefineTypeBool(TypeDef.TypeBoolName);
        }

        #endregion

        //---------------------------------------------------------------------
        public IType DefineTypeVoid()
        {
            // already exists?
            if (_typeMgr.TypeVoid != null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(TypeDef.TypeVoidName) != null)
                return null;

            // create the type
            ITypeVoid typeVoid = _factoryMgr.FactoryType.CreateTypeVoid(TypeDef.TypeVoidName);
            if (!_typeMgr.AddTypeVoid(typeVoid))
                return null;

            return typeVoid;

        }

        //=====================================================================
        #region Public Create type dataStruct methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create the type Structure, to be possible to create Structure instance.
        /// Its a generic type.
        /// </summary>
        /// <returns></returns>
        public ITypeStruct DefineTypeStruct()
        {
            string name = TypeDef.TypeStructName;
            if (string.IsNullOrWhiteSpace(name))
                return null;

            // not already exists?
            if (_typeMgr.TypeStruct != null)
                return _typeMgr.TypeStruct;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type
            ITypeStruct typeStruct = _factoryMgr.FactoryType.CreateTypeStruct(name);
            if (!_typeMgr.AddTypeStruct(typeStruct))
                return null;

            return typeStruct;
        }
        #endregion


        //=====================================================================
        #region Public Create type Enum methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create typeLOV, set the type of values (basic type only here).
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public TypeEnumBasic CreateTypeEnum(string name, ITypeBasic type, TypeEnumSelectMode selectMode)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            if (type == null)
                return null;

            // check that the name is not already used by another type
            if (_typeFinder.FindTypeByName(name) != null)
                return null;

            // create the type Enum
            TypeEnumBasic typeEnum = null;
            if(_typeFinder.IsTypeString(type))
            {
                typeEnum = _factoryMgr.FactoryType.CreateTypeEnumString(name, type, selectMode);
                if (!_typeMgr.AddTypeEnum(typeEnum))
                    return null;
            }

            if (!_typeMgr.AddTypeEnum(typeEnum))
                return null;

            return typeEnum;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Create typeLOV, values are typeof string.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public TypeEnumString CreateTypeEnumString(string name, TypeEnumSelectMode selectMode)
        {
            return CreateTypeEnum(name, _typeFinder.GetTypeString(), selectMode) as TypeEnumString;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Create typeLOV, values are typeof string.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public TypeEnumString CreateTypeEnumString(string name)
        {
            return CreateTypeEnum(name, _typeFinder.GetTypeString(), TypeEnumSelectMode.Single) as TypeEnumString;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Remove a TypeLOV by the name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool RemoveTypeEnumByName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return false;

            ITypeEnum typeEnum= _typeFinder.FindTypeEnumByName(name);
            if(typeEnum==null)
                return false;

            return _typeMgr.RemoveTypeEnum(typeEnum);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Add a string value to the type LOVString.
        /// </summary>
        /// <param name="typeEnum"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool AddEnumValue(ITypeEnumString typeEnum, string value)
        {
            if (typeEnum == null)
                return false;
            if (string.IsNullOrWhiteSpace(value))
                return false;

            // check that is not already added
            IValue dvValue= _typeFinder.FindValueInTypeEnum(typeEnum, value);
            if (dvValue != null)
                return false;

            // create a DV to save the string value
            ValueString dv = _factoryMgr.FactoryValue.CreateValueString(value);

            // save the datavalue to the LOV list
            return typeEnum.AddItem(dv);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Remove a string enum Value.
        /// </summary>
        /// <param name="typeEnum"></param>
        /// <param name="?"></param>
        /// <returns></returns>
        public bool RemoveEnumValue(ITypeEnum typeEnum, string value)
        {
            if (typeEnum == null)
                return false;
            if (string.IsNullOrWhiteSpace(value))
                return false;

            // check that the typeLOV type value is string (DataValueString)
            // TODO:

            //DataValueString dv= _factoryMgr.FactoryDataValue.CreateDataValueString(value);
            // get the DV in the typeLOV
            foreach(ValueString dv in typeEnum.ListItems)
            {
                if(dv.IsEqualsTo(value))
                {
                    typeEnum.Remove(dv);
                    return true;
                }
            }

            return false;
            //DataValueString dv= typeLOV.ListItems.Fin        
                
            // remove a value, by pos        bool RemoveByPos(int pos);


            // remove the value
            // TODO:
        }

        //---------------------------------------------------------------------
        public bool RemoveEnumValueByPos(ITypeEnum typeEnum, int pos)
        {
            if (typeEnum == null)
                return false;

            return typeEnum.RemoveByPos(pos);

        }
        #endregion

        //=====================================================================
        #region Public Edit type PhysQty methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Define one physical quantity type: Length, Time, Mass, temperature,...  
        /// can be define/created only one time.
        /// 
        /// Will give the possibility to create data (values, named) of this type.
        /// </summary>
        /// <returns></returns>
        public TypePhyLength DefineTypePhyLength()
        {
            // already exists?
            if (_typeFinder.GetTypePhyLength() != null)
                return null;

            // create the type
            return CreateTypePhyLength();
        }

        #endregion

        //=====================================================================
        #region Public Edit ListType dataStruct methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create (and save) a new list to save types.
        /// </summary>
        /// <param name="listName"></param>
        /// <returns></returns>
        public ListType CreateListType(string listName)
        {
            if (string.IsNullOrWhiteSpace(listName))
                return null;

            // check if the name is not already used by a list
            if (_typeFinder.FindListTypeByName(listName) != null)
                return null;

            // create the list and save it
            ListType listType = new ListType(listName);
            if (!_typeMgr.AddListType(listType))
                return null;

            return listType;
        }

        #endregion

        //=====================================================================
        #region Private methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create the type phys qty length.
        /// If hehre, not already exists, (checked before).
        /// </summary>
        /// <returns></returns>
        private TypePhyLength CreateTypePhyLength()
        {
            // create the type length
            TypePhyLength physQty = new TypePhyLength(_factoryMgr.IdFactory.CreateId(TypeDef.TypePhyLengthId), TypeDef.TypePhyLengthName);

            // save it in the mgr
            if (!_typeMgr.AddTypePhyLength(physQty))
                return null;

            // return it
            return physQty;
        }

        #endregion
    }
}
